#pragma once

#include <iostream>
#include <unordered_set>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "LogMessage.hpp"
#include "ExistReason.hpp"

std::unordered_set<std::string> forbid = {
    "rm",
    "mv",
    "kill",
    "cp"
};

class EchoServer
{
public:
    EchoServer(const uint16_t &port, const std::string &str = "")
    {
        // 创建套接字
        _socket = socket(AF_INET, SOCK_DGRAM, 0);
        if (_socket < 0)
        {
            Log::LogMessage(Error, "create socket error");
            exit(CREATE_SOCKET_ERROR);
        }
        Log::LogMessage(Debug, "create socket success, socket: %d", _socket);

        // 进行bind
        sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(port);
        addr.sin_addr.s_addr = str.empty() ? INADDR_ANY : inet_addr(str.c_str());

        int n = bind(_socket, (sockaddr *)&addr, sizeof(addr));
        if (n < 0)
        {
            Log::LogMessage(Error, "bind error");
            exit(BIND_ERROR);
        }
        Log::LogMessage(Debug, "bind success");
    }

    ~EchoServer()
    {
        close(_socket);
    }

    void Start()
    {
        while (true)
        {
            // 回显客户端消息即可
            ExecuteCommand();
        }
    }

private:
    void ExecuteCommand()
    {
        while (true)
        {
            char temp[1024];
            sockaddr_in addr;
            memset(&addr, 0, sizeof(addr));
            socklen_t addrlen = sizeof(addr);
            int n = recvfrom(_socket, temp, sizeof(temp) - 1, 0, (sockaddr *)&addr, &addrlen);
            std::string ip = inet_ntoa(addr.sin_addr);
            uint16_t port = ntohs(addr.sin_port);
            if (n > 0)
            {
                // 接收到数据
                temp[n] = '\0';
                std::string buffer = temp;
                // 对数据做处理
                // EchoMessage(buffer);      //echo
                // Transformed(buffer);      //小写转大写
                ExecuteCommand(buffer); // 执行用户命令

                // 将数据写回
                sendto(_socket, buffer.c_str(), buffer.size(), 0, (sockaddr *)&addr, sizeof(addr));
            }
            else if (n == 0)
            {
                // 对端关闭连接
                Log::LogMessage(Debug, "%s %d close connection", ip.c_str(), port);
            }
            else
            {
                Log::LogMessage(Warning, "server recvfrom warning");
            }
        }
    }

    void EchoMessage(std::string &buffer)
    {
        return;
    }

    void Transformed(std::string &buffer)
    {
        for (auto &ch : buffer)
        {
            if ('a' <= ch && ch <= 'z')
            {
                ch -= 32;
            }
        }
        return;
    }

    void ExecuteCommand(std::string &buffer)
    {
        // 查询有无禁止命令
        if (!sercharforbid(buffer))
        {
            buffer = "you can't do that\n";
            return;
        }

        // 使用popen执行用户命令，并将结果写入fp中
        if (buffer == "ll")
        {
            buffer = "ls -l --color=auto";
        }
        FILE *fp = popen(buffer.c_str(), "r");
        if (fp == nullptr)
        {
            buffer = "command is unknow";
            return;
        }
        // 读取信息
        buffer.clear();
        char temp[1024];
        while (fgets(temp, sizeof(temp), fp) != NULL)
        {
            buffer += temp;
        }

        pclose(fp);
    }

    bool sercharforbid(const std::string &buffer)
    {
        for (auto com : forbid)
        {
            int pos = buffer.find(com);
            if (pos != std::string::npos)
            {
                return false;
            }
        }

        return true;
    }

private:
    int _socket;
};